# -*- encoding: utf-8 -*-
"""
@File    : builder.py
@Author  : lilong
@Time    : 2021/12/18 7:17 下午
"""

"""
参考：https://www.cnblogs.com/-wenli/p/10965106.html

建造者模式（Builder Pattern）：
又名生成器模式，是一种对象构建模式。它可以将复杂对象的建造过程抽象出来（抽象类别），使这个抽象过程的不同实现方法可以构造出不同表现（属性）的对象。

建造者模式：
是一步一步创建一个复杂的对象，它允许用户只通过指定复杂对象的类型和内容就可以构建它们，用户不需要知道内部的具体构建细节。

主要解决：
主要解决在软件系统中，有时候面临着"一个复杂对象"的创建工作，其通常由各个部分的子对象用一定的算法构成；
由于需求的变化，这个复杂对象的各个部分经常面临着剧烈的变化，但是将它们组合在一起的算法却相对稳定。

何时使用：
一些基本部件不会变，而其组合经常变化的时候。

如何解决：将变与不变分离开。

关键代码：
建造者：创建和提供实例；
指挥者：管理建造出来的实例的依赖关系；

应用实例： 去肯德基，汉堡、可乐、薯条、炸鸡翅等是不变的，而其组合是经常变化的，生成出所谓的"套餐"。
优点： 1、建造者独立，易扩展。 2、便于控制细节风险。
缺点： 1、产品必须有共同点，范围有限制。 2、如内部变化复杂，会有很多的建造类。
使用场景： 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

注意事项：
与工厂模式的区别是：建造者模式更加关注与零件装配的顺序。

"""


# ========具体产品对象=======
class Menu:
    """菜单类"""

    Menu_A = []
    Menu_B = []

    def set_MenuA(self, item):
        self.Menu_A.append(item)

    def set_MenuB(self, item):
        self.Menu_B.append(item)

    def get_MenuA(self):
        return self.Menu_A

    def get_MenuB(self):
        return self.Menu_B


# ========Builder：抽象类，创建一个Product对象的各个部件指定的抽象接口=======
class Product:

    product = Menu()

    def build_hanbao(self):
        pass

    def build_jiroujuan(self):
        pass

    def build_kele(self):
        pass

    def build_shutiao(self):
        pass


# ConcreteBuilder（具体建造者）实现抽象接口，构建和装配各个部件
class product_A(Product):
    def __init__(self):
        self.producttype = "A"

    def build_hanbao(self):
        self.hanbao = "汉堡"
        self.product.set_MenuA(self.hanbao)

    def build_kele(self):
        self.kele = "可乐"
        self.product.set_MenuA(self.kele)

    def getType(self):
        return self.producttype


class product_B(Product):
    def __init__(self):
        self.producttype = "B"

    def build_shutiao(self):
        self.shutiao = "薯条"
        self.product.set_MenuB(self.shutiao)

    def build_jiroujuan(self):
        self.jiroujuan = "鸡肉卷"
        self.product.set_MenuB(self.jiroujuan)

    def build_kele(self):
        self.kele = "可乐"
        self.product.set_MenuB(self.kele)

    def getType(self):
        return self.producttype


# =======Director（指挥者）========
class Make:
    """很重要的一个类"""

    def __init__(self):
        self.builder = None

    def build_product(self, builder):
        self.builder = builder
        print(builder.producttype)
        if builder.producttype == "A":
            [step() for step in (builder.build_hanbao,
                                 builder.build_kele)]
        if builder.producttype == "B":
            [step() for step in (builder.build_shutiao,
                                 builder.build_jiroujuan,
                                 builder.build_kele)]


# 不同类型选择
def validate_style(builders):
    """验证类型"""

    global valid_input

    try:
        print('套餐A：汉堡、可乐' + '套装B：薯条、鸡肉卷、可乐')
        product_style = input('请输入您的选择：')
        builder = builders[product_style]()
        valid_input = True

    except KeyError as err:
        print('Sorry, 没有这个套餐，请重新选择。')
        return (False, None)

    return (True, builder, product_style)


# 主函数：逻辑代码
def main():

    # 建造者集合
    builders = dict(A=product_A, B=product_B)

    # 验证输入
    valid_input = False
    while not valid_input:
        valid_input, builder, product_style = validate_style(builders)

    Waiter = Make()
    Waiter.build_product(builder)

    if product_style == "A":
        print(builder.product.get_MenuA())
    else:
        print(builder.product.get_MenuB())


if __name__ == "__main__":
    main()
